﻿using SignalBox.Core.Util;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace SignalBox.Core
{
    public class TrackCellType
    {
        private static Dictionary<TRACKCELLTYPE, TrackCellType> trackCellTypes;
        static TrackCellType()
        {
            trackCellTypes = new Dictionary<TRACKCELLTYPE, TrackCellType>();
            loadTrackCellTypes();
        }

        private Dictionary<int, string> overlayBitmaps;

        public static Dictionary<TRACKCELLTYPE, TrackCellType> TrackCellTypes
        {
            get
            {
                return trackCellTypes;
            }
        }

        public Bitmap GetToolboxImage()
        {
            return (Bitmap)Toolbox.ResourceManager.GetObject(ToolbarBitmap.Replace(".bmp", ""));
        }

        public Bitmap GetOverlayImage(int state)
        {
            if (overlayBitmaps.ContainsKey(state))
            {
                return (Bitmap)Toolbox.ResourceManager.GetObject(overlayBitmaps[state].Replace(".bmp", ""));
            }

            return null;
        }

        public Bitmap GetBaseImage()
        {
            return (Bitmap)Toolbox.ResourceManager.GetObject(BaseBitmap.Replace(".bmp", ""));
        }
        public TrackCellType(TRACKCELLTYPE tct)
        {
            TheTrackCellType = tct;
            overlayBitmaps = new Dictionary<int, string>();

            LoadFromTo();

        }

        private Dictionary<int, Dictionary<DIRECTION, DIRECTION>> routes;

        private void LoadFromTo()
        {
            routes = new Dictionary<int, Dictionary<DIRECTION, DIRECTION>>();
            string name = TheTrackCellType.ToString();
            string[] parts = name.Split("_".ToCharArray());

            if (parts.Length == 2)
            {
                DIRECTION dir1 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[1]);
                routes[1] = new Dictionary<DIRECTION, DIRECTION>();
                routes[1][dir1] = RouteFinding.GetOppositeDirection(dir1);
                routes[1][RouteFinding.GetOppositeDirection(dir1)] = dir1;

            }
            else if (parts.Length == 3)
            {
                DIRECTION dir1 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[1]);
                DIRECTION dir2 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[2]);

                routes[1] = new Dictionary<DIRECTION, DIRECTION>();
                routes[1][dir1] = dir2;
                routes[1][dir2] = dir1;
            }
            else if (parts.Length == 4)
            {
                DIRECTION dir1 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[1]);
                DIRECTION dir2 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[2]);
                DIRECTION dir3 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[3]);

                routes[1] = new Dictionary<DIRECTION, DIRECTION>();
                routes[1][dir1] = dir2;
                routes[1][dir2] = dir1;
                routes[2] = new Dictionary<DIRECTION, DIRECTION>();
                routes[2][dir1] = dir3;
                routes[2][dir3] = dir1;

            }
            else if (parts.Length == 5)
            {
                DIRECTION dir1 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[1]);
                DIRECTION dir2 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[2]);
                DIRECTION dir3 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[3]);
                DIRECTION dir4 = (DIRECTION)Enum.Parse(typeof(DIRECTION), parts[4]);

                routes[1] = new Dictionary<DIRECTION, DIRECTION>();
                routes[1][dir1] = dir2;
                routes[1][dir2] = dir1;
                routes[2] = new Dictionary<DIRECTION, DIRECTION>();
                routes[2][dir3] = dir4;
                routes[2][dir4] = dir3;
            }
        }

        public TRACKCELLTYPE TheTrackCellType
        {
            get;
            set;
        }

        public string ToolbarBitmap
        {
            get;
            set;
        }

        public string ToolbarName
        {
            get;
            set;
        }

        public string BaseBitmap
        {
            get;
            set;
        }

        public string Category
        {
            get;
            set;
        }

        public bool HasE
        {
            get;
            set;
        }

        public bool HasN
        {
            get;
            set;
        }
        public bool HasS
        {
            get;
            set;
        }
        public bool HasW
        {
            get;
            set;
        }
        public bool HasNE
        {
            get;
            set;
        }
        public bool HasSE
        {
            get;
            set;
        }

        public bool HasSW
        {
            get;
            set;
        }

        public bool HasNW
        {
            get;
            set;
        }

        protected void AddOverlayBitmap(int state, string bitmap)
        {
            overlayBitmaps[state] = bitmap;
        }

        private static void loadTrackCellTypes()
        {
            XDocument xml = XDocument.Parse(Toolbox.TrackElements);

            foreach (XElement node in xml.Root.Elements("TrackElement"))
            {
                String type = node.Element("TrackCellType").Value;
                TRACKCELLTYPE tctype = (TRACKCELLTYPE)Enum.Parse(typeof(TRACKCELLTYPE), type, true);

                TrackCellType tct = new TrackCellType(tctype);
                tct.ToolbarBitmap = node.Element("TrackToolBitmap").Value;
                tct.ToolbarName = node.Element("TrackToolName").Value;
                tct.BaseBitmap = node.Element("BaseBitmap").Value;
                tct.Category = node.Element("Category").Value;
                tct.HasE = bool.Parse(node.Element("Connections").Element("E").Value);
                tct.HasN = bool.Parse(node.Element("Connections").Element("N").Value);
                tct.HasW = bool.Parse(node.Element("Connections").Element("W").Value);
                tct.HasS = bool.Parse(node.Element("Connections").Element("S").Value);
                tct.HasNE = bool.Parse(node.Element("Connections").Element("NE").Value);
                tct.HasSE = bool.Parse(node.Element("Connections").Element("SE").Value);
                tct.HasSW = bool.Parse(node.Element("Connections").Element("SW").Value);
                tct.HasNW = bool.Parse(node.Element("Connections").Element("NW").Value);

                foreach (XElement nOverlay in node.Element("Overlays").Elements("Overlay"))
                {
                    int state = int.Parse(nOverlay.Element("State").Value);
                    String bitmap = nOverlay.Element("Bitmap").Value;
                    tct.AddOverlayBitmap(state, bitmap);
                }

                trackCellTypes[tctype] = tct;
            }
        }

        public int numberOfConnections()
        {
            int num = 0;

            if (HasN) num++;
            if (HasE) num++;
            if (HasS) num++;
            if (HasW) num++;
            if (HasNE) num++;
            if (HasNW) num++;
            if (HasSE) num++;
            if (HasSW) num++;

            return num;
        }


        public DIRECTION GetSignalDirectionOutput(TRACKCELLTYPE tt)
        {
            switch (tt)
            {
                case TRACKCELLTYPE.SIGNAL_E_W:
                    return DIRECTION.W;
                case TRACKCELLTYPE.SIGNAL_N_S:
                    return DIRECTION.S;
                case TRACKCELLTYPE.SIGNAL_NE_SW:
                    return DIRECTION.SW;
                case TRACKCELLTYPE.SIGNAL_NW_SE:
                    return DIRECTION.SE;
                case TRACKCELLTYPE.SIGNAL_S_N:
                    return DIRECTION.N;
                case TRACKCELLTYPE.SIGNAL_SE_NW:
                    return DIRECTION.NW;
                case TRACKCELLTYPE.SIGNAL_SW_NE:
                    return DIRECTION.NE;


            }

            return DIRECTION.E;
        }

        public Dictionary<DIRECTION, DIRECTION> GetRoutes(int state)
        {
            if (routes.ContainsKey(state))
                return routes[state];
            return routes[1];
        }

        public DIRECTION GetOutputDirectionForInput(DIRECTION input, int state)
        {

           

            if (!routes.ContainsKey(state))
                state = 1;

            if (!routes.ContainsKey(state))
                return DIRECTION.INVALID;

            if (!routes[state].ContainsKey(input))
                return DIRECTION.INVALID;

            return routes[state][input];
        }

        public DIRECTION GetOutputDirectionForEntry()
        {
            if (TheTrackCellType == TRACKCELLTYPE.ENTRY_E)
            {
                return DIRECTION.W;
            }
            else if (TheTrackCellType == TRACKCELLTYPE.ENTRY_N)
            {
                return DIRECTION.S;
            }
            else if (TheTrackCellType == TRACKCELLTYPE.ENTRY_S)
            {
                return DIRECTION.N;
            }
            else if (TheTrackCellType == TRACKCELLTYPE.ENTRY_W)
            {
                return DIRECTION.E;
            }
            return DIRECTION.INVALID;
        }
    }
}
